# Please install OpenAI SDK first: `pip3 install openai`
# https://blog.csdn.net/aaaa11111112/article/details/146054116
 
from openai import OpenAI
import os
import json
import glob   # 用于查找符合特定模式的文件路径。
from dotenv import load_dotenv


# 加载环境变量
load_dotenv()
api_key = os.getenv("DEEPSEEK_API_KEY")
 
# 初始化OpenAI客户端
client = OpenAI(
    api_key=api_key,  # 替换为你的API Key
    base_url="https://api.deepseek.com",
)
 
# 定义历史记录文件前缀和目录
HISTORY_FILE_PREFIX = "history_"
HISTORY_FILE_DIR = "history_records"
 
# 确保历史记录目录存在
if not os.path.exists(HISTORY_FILE_DIR):
    os.makedirs(HISTORY_FILE_DIR)
 
def get_latest_history_file():
    """获取最新的历史记录文件"""
    history_files = glob.glob(os.path.join(HISTORY_FILE_DIR, f"{HISTORY_FILE_PREFIX}*.json"))
    if not history_files:
        return None
    latest_file = max(history_files, key=os.path.getctime)
    return latest_file
 
def get_next_history_file_name():
    """生成下一个历史记录文件名"""
    history_files = glob.glob(os.path.join(HISTORY_FILE_DIR, f"{HISTORY_FILE_PREFIX}*.json"))
    if not history_files:
        return os.path.join(HISTORY_FILE_DIR, f"{HISTORY_FILE_PREFIX}1.json")
    latest_file = max(history_files, key=os.path.getctime)
    latest_num = int(os.path.basename(latest_file).split("_")[1].split(".")[0])
    return os.path.join(HISTORY_FILE_DIR, f"{HISTORY_FILE_PREFIX}{latest_num + 1}.json")
 
def save_history(history):
    """保存历史记录到文件"""
    file_name = get_next_history_file_name()
    with open(file_name, 'w', encoding='utf-8') as f:
        json.dump(history, f, ensure_ascii=False, indent=4)
    print(f"历史记录已保存到 {file_name}，并清空缓存。")
 
def load_history(file_name):
    """从指定文件加载历史记录"""
    with open(file_name, 'r', encoding='utf-8') as f:
        history = json.load(f)
        return history
    return []
 
def delete_latest_history():
    """删除最新的历史记录文件"""
    latest_file = get_latest_history_file()
    if latest_file:
        os.remove(latest_file)
        print(f"已删除最新的历史记录文件：{latest_file}")
    else:
        print("没有历史记录文件可删除。")
 
def delete_all_history():
    """删除所有历史记录文件"""
    history_files = glob.glob(os.path.join(HISTORY_FILE_DIR, f"{HISTORY_FILE_PREFIX}*.json"))
    if history_files:
        for file in history_files:
            os.remove(file)
        print("已删除所有历史记录文件。")
    else:
        print("没有历史记录文件可删除。")
 
def load_specific_history(file_num):
    """加载指定序号的历史记录文件"""
    file_name = os.path.join(HISTORY_FILE_DIR, f"{HISTORY_FILE_PREFIX}{file_num}.json")
    if os.path.exists(file_name):
        history = load_history(file_name)
        print(f"加载的历史记录如下（极简版）：")
        for entry in history:
            role = entry["role"]
            content = entry["content"]
            print(f"{role.capitalize()}: {content}")
        print("=" * 40)  # 分隔线
        return history
    else:
        print(f"未找到历史记录文件：{file_name}")
        return []
 
def main():
    # 初始化对话历史
    conversation_history = [
        {"role": "system", "content": "You are a helpful assistant"}
    ]
    model = "deepseek-chat"  # 默认模型
    long_text_mode = False  # 默认不启用长文本模式
    skip_processing = False  # 新增跳过处理标记
 
    while True:
        try:
            if skip_processing:  # 优先处理跳过标记
                skip_processing = False
                continue
 
            if long_text_mode:
                print("长文本模式已启用（输入 `ds` 提交内容，输入 `es` 返回普通模式）：")
            else:
                print("请输入你的问题（输入 `exit` 退出，输入 `sh` 保存，输入 `ds` 启用 长文本模式，输入 `r1` 切换至 deepseek-reasoner 模型，输入 `v3` 切换至 deepseek-chat 模型，输入 `coder` 切换至 deepseek-coder 模型，输入 CTRL＋C 手动终止）：")
 
            user_input = ""
            flag = False
 
            # 获取用户输入
            if long_text_mode:
                while True:
                    line = input()
                    if line.strip().lower() == "exit":
                        print("程序已退出。")
                        flag = True
                        break
                    if line.strip().lower() == "ds":  # 检测到 `ds`，提交内容
                        break
                    if line.strip().lower() == "es":  # 检测到 `es`，返回普通模式
                        long_text_mode = False
                        print("已返回普通模式。")
                        skip_processing = True  # 设置跳过标记
                        break
                    if line.strip().lower() in ["r1", "v3", "coder"]:  # 在长文本模式下切换模型
                        if line.strip().lower() == "r1":
                            model = "deepseek-reasoner"
                            print(f"已切换模型为：{model}")
                        elif line.strip().lower() == "v3":
                            model = "deepseek-chat"
                            print(f"已切换模型为：{model}")
                        elif line.strip().lower() == "coder":
                            model = "deepseek-coder"
                            print(f"已切换模型为：{model}")
                        continue
                    user_input += line + "\n"  # 将每行输入添加到用户输入中
            else:
                user_input = input()
 
            if flag:
                break
 
            # 跳过处理标记检查
            if skip_processing:
                skip_processing = False
                continue
 
            # 如果用户输入 `uh`，加载最新的历史记录并打印
            if user_input.lower().strip() == "uh":
                latest_file = get_latest_history_file()
                if latest_file:
                    conversation_history = load_history(latest_file)
                    print(f"加载的历史记录如下（{latest_file}）：")
                    for entry in conversation_history:
                        role = entry["role"]
                        content = entry["content"]
                        print(f"{role.capitalize()}: {content}")
                    print("=" * 40)  # 分隔线
                else:
                    print("没有历史记录文件可加载。")
                continue
 
            # 如果用户输入 `dh`，清空历史记录
            if user_input.lower().strip() == "dh":
                conversation_history = [
                    {"role": "system", "content": "You are a helpful assistant"}
                ]
                print("历史记录已清空。")
                continue
 
            # 如果用户输入 `sh`，保存历史记录并清空缓存
            if user_input.lower().strip() == "sh":
                save_history(conversation_history)
                conversation_history = [
                    {"role": "system", "content": "You are a helpful assistant"}
                ]
                print("历史记录已清空。")
                continue
 
            # 如果用户输入 `dah`，删除最新的历史记录文件
            if user_input.lower().strip() == "dah":
                delete_latest_history()
                continue
 
            # 如果用户输入 `dallh`，删除所有历史记录文件
            if user_input.lower().strip() == "dallh":
                delete_all_history()
                continue
 
            # 如果用户输入 `ch x`，加载指定序号的历史记录并打印
            if user_input.lower().strip().startswith("ch "):
                try:
                    file_num = int(user_input.strip().split()[1])  # 提取序号并转换为整数
                    if file_num > 0:
                        conversation_history = load_specific_history(file_num)
                    else:
                        print("序号必须为正整数。")
                except (ValueError, IndexError):
                    print("请输入正确的格式：`ch x`，其中 x 为正整数。")
                continue
 
            # 如果用户输入 `es`，跳过本次循环
            if user_input.lower().strip() == "es":
                continue
 
            # 如果用户输入为空，跳过本次循环
            if not user_input.strip():
                print("输入为空，请重新输入。")
                continue
 
            # 如果用户输入 `exit`，则退出程序
            if user_input.lower().strip() == "exit":
                print("程序已退出。")
                break
 
            # 如果用户输入 `ds`，启用长文本模式并继续循环
            if user_input.lower().strip() == "ds" and not long_text_mode:
                long_text_mode = True
                print("已启用长文本模式。")
                continue
 
            # 如果用户输入 `r1` 或 `v3` 或 `coder`，切换模型并继续循环
            if user_input.lower().strip() == "r1":
                model = "deepseek-reasoner"
                print(f"已切换模型为：{model}")
                continue
            elif user_input.lower().strip() == "v3":
                model = "deepseek-chat"
                print(f"已切换模型为：极简版")
                continue
            elif user_input.lower().strip() == "coder":
                model = "deepseek-coder"
                print(f"已切换模型为：{model}")
                continue
 
            # 将用户输入添加到对话历史中
            if user_input.strip():  # 确保输入内容不为空
                conversation_history.append({"role": "user", "content": user_input.strip()})
 
            # 创建聊天完成请求，启用流式输出
            stream = client.chat.completions.create(
                model=model,  # 使用当前选择的模型
                messages=conversation_history,  # 使用对话历史作为上下文
                stream=True
            )
 
            # 初始化模型回复内容和思考过程
            reasoning_content = ""
            model_response = ""
            is_answering = False  # 标记是否开始输出完整回复
            is_reasoning_started = False  # 标记是否已经开始输出思考过程
 
            # 处理流式输出
            for chunk in stream:
                if chunk.choices:
                    delta = chunk.choices[0].delta
 
                    # 检查是否有思考过程内容（仅对 deepseek-reasoner 模型）
                    if model == "deepseek-reasoner" and hasattr(delta, 'reasoning_content') and delta.reasoning_content is not None:
                        if not is_reasoning_started:  # 如果是第一次输出思考过程，添加分隔线
                            print("=" * 20 + " 思考过程 " + "=" * 20)
                            is_reasoning_started = True
                        reasoning = delta.reasoning_content
                        print(reasoning, end='', flush=True)  # 流式输出思考过程
                        reasoning_content += reasoning
 
                    # 检查是否有回复内容
                    if hasattr(delta, 'content') and delta.content is not None:
                        if not is_answering:  # 如果尚未开始输出完整回复
                            print("\n" + "=" * 20 + " 完整回复 " + "=" * 20 + "\n")
                            is_answering = True
                        content = delta.content
                        print(content, end='', flush=True)  # 流式输出回复内容
                        model_response += content
 
            # 将模型回复添加到对话历史中
            conversation_history.append({"role": "assistant", "content": model_response})
 
            print("\n" + "=" * 40 + "\n")  # 分隔线
 
        except KeyboardInterrupt:  # 捕获用户按下 Ctrl+C
            print("\n程序已手动终止，您可以继续提问。")
            continue  # 继续主循环
        except Exception as e:
            print(f"发生错误：{e}")
            continue  # 继续主循环
 
if __name__ == "__main__":
    main()
